#ifndef GLOBALCONFIG_H
#define GLOBALCONFIG_H

#include <QObject>
#include <QScreen>
#include <QApplication>
#include <QTimer>
#include <QDebug>

#include <mutex>
#include <condition_variable>
#include <thread>
#include <unordered_map>
#include <atomic>
#include <tuple>

#include "dmcomm.h"
#include "xx/typedef.h"
#include "bimap.h"

// 定义复合键：由cmd_1、cmd_2、cmd_3组成，标识同类型数据
using CmdKey = std::tuple<uint8_t, uint8_t, uint8_t>;
// 定义消息结构：存储发送所需的完整数据
struct CmdMessage {
    uint8_t cmd_1;
    uint8_t cmd_2;
    uint8_t cmd_3;
    std::vector<uint8_t> data;
};
// 哈希函数
struct CmdKeyHash {
    size_t operator()(const CmdKey& key) const {
        auto [c1, c2, c3] = key;
        // 组合三个cmd的哈希值
        size_t hash1 = std::hash<uint8_t>{}(c1);
        size_t hash2 = std::hash<uint8_t>{}(c2);
        size_t hash3 = std::hash<uint8_t>{}(c3);
        return hash1 ^ (hash2 << 1) ^ (hash3 << 2);
    }
};

class GlobalConfig : public QObject
{
    Q_OBJECT
private:
    explicit GlobalConfig(QObject *parent = nullptr);
    ~GlobalConfig();

    GlobalConfig(const GlobalConfig&) = delete;
    GlobalConfig& operator=(const GlobalConfig&) = delete;
    GlobalConfig(GlobalConfig&&) = delete;
    GlobalConfig& operator=(GlobalConfig&&) = delete;

    static std::atomic<bool> s_initialized;
public:
    static GlobalConfig& getInstance();
    static std::vector<uint8_t> uint16ToBytes(const uint16_t &data);
signals:
    void connected(DevInfo);
    void disconnected(DevInfo);
    void errorOccurred();
    void initialized();
    void peak(const stCfgPeak &);
    void sceneNameUpdated();
    void inputNameUpdated();
    void outputNameUpdated();
    void loaded();
    void saved();
    void imported(uint8_t);
    void exported(uint8_t cmd3, const std::vector<uint8_t> &data);
    void refresh();
public slots:
    void windowClosed();
    void open(const DevInfo &info);
    void close(const DevInfo &info);

    /**
     * @brief 通道数据
     * @param channel 通道
     * @param value 写入值
     */
    void mute(uint8_t channel, uint8_t value);
    void phase(uint8_t channel, uint8_t value);
    void gain(uint8_t channel, uint16_t value);
    void delay(uint8_t channel, uint16_t value);
    void compressor(uint8_t channel, const stDataCmps &value);
    void limiter(uint8_t channel, const stDataLimt &value);
    void noiseGate(uint8_t channel, const stDataNsgt &value);
    /**
     *  @param type 0->HPF 1->LPF
     */
    void xover(uint8_t channel, uint8_t type, const stDataXover &value);
    /**
     *  @param type EQ[0-N]
     */
    void peq(uint8_t channel, uint8_t type, const stDataEq &value);
    /**
     *  @param channel 输出通道
     *  @param type 输入通道
     */
    void mixer(uint8_t channel, uint8_t type, const stDataMixer &value);

    // 读设备信息
    void readInfo();
    // 读电平
    void readPeak();

    /**
     * @brief 系统数据
     * @param id 00-自定义  01-密码  02-网络  03-蓝牙  FF-全部（默认FF，一次性读取数据）
     */
    void readSystem(uint8_t id);
    void writeSystem(uint8_t id, const std::vector<uint8_t> &data);

    /**
     * @brief 名称配置
     * @param id 00-设备  01-场景  02-输入通道  03-输出通道  FF-全部（默认FF）
     * @param index 对应编号
     * @param value 名称
     */
    void readName(uint8_t id);
    void writeDeviceName(const QString &value);
    void writeSceneName(uint8_t index, const QString &value);
    void writeInputName(uint8_t index, const QString &value);
    void writeOutputName(uint8_t index, const QString &value);

    /**
     * @brief 场景
     * @param index 0~N 场景编号 0 当前场景
     */
    void loadScene(uint8_t index);
    void saveScene(uint8_t index);
    void exportScene(uint8_t index);
    void importScene(uint8_t index, const std::vector<uint8_t> &data);
    void copyChannel(uint8_t source, uint8_t target);

    /**
     * @brief 联调
     * @param channel 通道
     * @param index 所在组 0-N
     */
    void group(uint8_t channel, uint8_t index);
public:
    stCfgDev cfgDev() const;
    stCfgData cfgData() const;
    stCfgName cfgName() const;
    PARAM_GROUP paramGroup() const;
    void demo();
private:
    void write(uint8_t cmd_1, uint8_t cmd_2, uint8_t cmd_3, const std::vector<uint8_t> &data);
    void recv(const std::vector<uint8_t> &msg);
    void error(const int &err);
    void save(const std::vector<uint8_t> &data, const QString &fileName) const;
    template <class T>
    void read(T &target, const QString &fileName);
    std::vector<uint8_t> strToBytes(const QString &data) const;
    template <class T>
    std::vector<uint8_t> toBytes(const T &data) const;
    template <class T>
    bool update(T &target, const std::vector<uint8_t> &source);
    template <typename T, typename MusSetter, typename OutSetter>
    void setChannel(uint8_t cmd_1, uint8_t channel, uint8_t type, T value, MusSetter musSetter, OutSetter outSetter);
    template <class T>
    void setName(T &target, const QString &source);
private:
    // 消息池
    std::atomic<bool> s_atomic;
    std::mutex m_mutex;
    std::condition_variable m_cv;
    std::thread m_thread;
    std::unordered_map<CmdKey, CmdMessage, CmdKeyHash> m_pool;
private:
    stCfgDev m_cfgDev;
    stCfgData m_cfgData;
    stCfgName m_cfgName;
    PARAM_GROUP m_paramGroup;
private:
    QTimer *timer;
    DevInfo m_info;
    QSet<uint8_t> m_flag;
    BiMap<uint8_t, uint8_t> m_input;
    BiMap<uint8_t, uint8_t> m_output;
    mutable stCfgPeak m_peak;
};

#endif // GLOBALCONFIG_H
